home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 20 code / Scripting the Finder / Finder Tricks / SendFinderTricks.cp < prev    next >
Encoding:
Text File  |  1994-10-04  |  23.1 KB  |  781 lines  |  [TEXT/MMCC]

  1. /*================================================================================
  2.     SendFinderTricks.cp
  3.     
  4.     ©1994 Greg Anderson
  5.     greggor@apple.com
  6.     
  7.     Send events to the Finder
  8.         
  9. ================================================================================*/
  10. #include "SendFinderTricks.h"
  11. #include "AppleEventUtilities.h"
  12. #include "AERegistry.h"
  13. #include "AEObjects.h"
  14. #include "FinderRegistry.h"
  15. #include "Exceptions.h"
  16.  
  17. //----------------------------------------------------------------------------------------
  18. // FindPSNbyTypeAndSig: 
  19. //
  20. //    Find the PSN of some process, given its type and creator
  21. //----------------------------------------------------------------------------------------
  22. void FindPSNbyTypeAndSig(ProcessSerialNumber* psn, OSType type, OSType sig)
  23. {    
  24.     ProcessInfoRec            theProc;
  25.         
  26.     //
  27.     // Start out with kNoProcess
  28.     //
  29.     psn->highLongOfPSN = 0;
  30.     psn->lowLongOfPSN = kNoProcess;
  31.     
  32.     //
  33.     // Initialize fields in the ProcessInfoRec,
  34.     // or we'll have memory hits in random locations
  35.     //
  36.     theProc.processInfoLength = sizeof( ProcessInfoRec );
  37.     theProc.processName = nil;
  38.     theProc.processAppSpec = nil;
  39.     theProc.processLocation = nil;
  40.     
  41.     while(true)
  42.     {
  43.         OSErr        theErr;
  44.         
  45.         //
  46.         // Keep looking for the Finder until we find it
  47.         //
  48.         FailErr(GetNextProcess(psn));
  49.         if( (psn->highLongOfPSN == 0) && (psn->lowLongOfPSN == kNoProcess) )
  50.             Throw(procNotFound);
  51.         
  52.         //
  53.         // Is the current process the one we're looking for?
  54.         //
  55.         FailErr(GetProcessInformation(psn, &theProc));
  56.         if( (theProc.processType == type ) && (theProc.processSignature == sig) )
  57.             break;
  58.     }
  59. } // FindPSNbyTypeAndSig 
  60.  
  61. TDescriptor GetAddressOfFinder();
  62.  
  63. #ifdef SOMEWHEREELSE
  64.  
  65. //----------------------------------------------------------------------------------------
  66. // GetAddressOfFinder: 
  67. //
  68. //    Generate an address for the Finder on this machine 
  69. //----------------------------------------------------------------------------------------
  70. TDescriptor GetAddressOfFinder()
  71. {
  72.     ProcessSerialNumber finderPSN;
  73.     TDescriptor finderAddressDescriptor;
  74.     
  75.     //
  76.     // Find the Finder's PSN
  77.     //
  78.     FindPSNbyTypeAndSig(&finderPSN, 'FNDR', 'MACS');
  79.     
  80.     //
  81.     // Copy the target ID into a descriptor
  82.     //
  83.     finderAddressDescriptor.MakeProcessSerialNumber(finderPSN);
  84.     
  85.     return finderAddressDescriptor;
  86. } // GetAddressOfFinder 
  87.  
  88. #endif
  89.  
  90. //----------------------------------------------------------------------------------------
  91. // MakeSpecifierForSelection
  92. //----------------------------------------------------------------------------------------
  93. TDescriptor MakeSpecifierForSelection()
  94. {
  95.     TDescriptor selectionSpecifier; 
  96.     TDescriptor nullDescriptor;
  97.     TDescriptor keyData;
  98.  
  99.     //
  100.     // Make a descriptor whose type is 'typeType' and whose
  101.     // contents are 'pSelection' (defined in FinderRegistry.h).
  102.     // This descriptor specifies the property of the null container
  103.     // that we are interested in--in this case, the selection.
  104.     //
  105.     keyData.MakeDescType(pSelection);
  106.     
  107.     //
  108.     // Make an object specifier for "selection of <null container>".
  109.     // The object specifier will contain the following:
  110.     //
  111.     // Desired class:        cProperty        Object specifiers that
  112.     //                                        specify properties always
  113.     //                                        have a desired class of cProperty
  114.     //
  115.     // Container:            null            A null descriptor specifies the
  116.     //                                        null container.  Object specifiers
  117.     //                                        almost always terminate with the
  118.     //                                        null descriptor, the only exceptions
  119.     //                                        being specifiers used to support
  120.     //                                        "paste reference," which terminate
  121.     //                                        in the PSN of the process that
  122.     //                                        generated them, and object specifiers
  123.     //                                        contained in test descriptors
  124.     //                                        (found in "whose" clauses) that
  125.     //                                        often terminate with "object being
  126.     //                                        examined".
  127.     //
  128.     // Key form:            formPropertyID    Object specifiers that specify properties
  129.     //                                        always have a key form of formPropertyID.
  130.     //
  131.     // Key data:            typeType /        The key data descriptor of a property
  132.     //                        pSelection        must always be of type typeType; in
  133.     //                                        our case, it is a descriptor that
  134.     //                                        contains pSelection (built above).
  135.     //
  136.     // We pass 'true' to MakeObjectSpecifier, so it will always dispose its inputs.
  137.     // If we passed in 'false', we would have to dispose of the keyData descriptor
  138.     // ourselves.
  139.     //
  140.     selectionSpecifier.MakeObjectSpecifier(cProperty, nullDescriptor, formPropertyID, keyData, true);
  141.  
  142.     return selectionSpecifier;
  143. } // MakeSpecifierForSelection
  144.  
  145. //----------------------------------------------------------------------------------------
  146. // MakeSpecifierForIndexedItem
  147. //----------------------------------------------------------------------------------------
  148. TDescriptor MakeSpecifierForIndexedItem(DescType desiredClass, long index, TDescriptor ofSpecifier)
  149. {
  150.     TDescriptor resultSpecifier; 
  151.     TDescriptor keyData;
  152.  
  153.     //
  154.     // Make a descriptor whose type is 'typeLongInteger' and whose
  155.     // contents is the index passed in.
  156.     //
  157.     keyData.MakeLong(index);
  158.     
  159.     //
  160.     // Make an object specifier for "<<class desiredClass>> index of <ofSpecifier>".
  161.     // The object specifier will contain the following:
  162.     //
  163.     // Desired class:        desiredClass            The class of the object being referenced;
  164.     //                                                examples include cWindow, cObject, cDisk,
  165.     //                                                cAliasFile, and many others
  166.     //
  167.     // Container:            ofSpecifier                Object specifiers are defined recursively
  168.     //
  169.     // Key form:            formAbsolutePosition    This indicates that we are accessing the
  170.     //                                                'index'th item of the container.  Another
  171.     //                                                choice would be formName, in which case
  172.     //                                                the key data would contain the name of the
  173.     //                                                object being referenced.
  174.     //
  175.     // Key data:            typeLongInteger /        formAbsolutePosition implies that the key data
  176.     //                        'index'                    will be an integer
  177.     //
  178.     // We pass 'false' to MakeObjectSpecifier, so our inputs are not disposed
  179.     // (we want to keep 'ofSpecifier' around).  Because we didn't ask MakeObjectSpecifier
  180.     // to delete our inputs, we'll have to delete the key data ourselves
  181.     //
  182.     resultSpecifier.MakeObjectSpecifier(desiredClass, ofSpecifier, formAbsolutePosition, keyData, false);
  183.     keyData.Dispose();
  184.  
  185.     return resultSpecifier;
  186. } // MakeSpecifierForSelection
  187.  
  188. //----------------------------------------------------------------------------------------
  189. // MakeSpecifierForFrontWindow
  190. //----------------------------------------------------------------------------------------
  191. TDescriptor MakeSpecifierForFrontWindow()
  192. {
  193.     TDescriptor nullDescriptor;
  194.     
  195.     return MakeSpecifierForIndexedItem(cWindow, 1, nullDescriptor);
  196. }
  197.  
  198. //----------------------------------------------------------------------------------------
  199. // MakeSpecifierForPropertyOfSpecifier: 
  200. //
  201. //    This function makes an object specifier for "property of <<specifier provided>>"
  202. //----------------------------------------------------------------------------------------
  203. TDescriptor MakeSpecifierForPropertyOfSpecifier(DescType property, TDescriptor ofSpecifier)
  204. {
  205.     TDescriptor specifier;
  206.     TDescriptor keyData;
  207.     OSErr err = noErr;
  208.         
  209.     //
  210.     // Make a descriptor whose type is 'typeType', and whose
  211.     // contents are the property passed into this function.
  212.     //
  213.     keyData.MakeDescType(property);
  214.  
  215.     Try
  216.     {
  217.         //
  218.         // The next object specifier we make also specifies a property, so it
  219.         // will look very similar to the one we built above:
  220.         //
  221.         // Desired class        cProperty        Required to specify a property.
  222.         //
  223.         // Container            "ofSpecifier"    We are making a specifier for
  224.         //                                        "property of <ofSpecifier>", so clearly
  225.         //                                        our container must be the
  226.         //                                        object specifier passed in.
  227.         //
  228.         // Key form:            formPropertyID    Required to specify a property.
  229.         //
  230.         // Key data                typeType /        As before, the key data descriptor
  231.         //                        property        is typeType, and contains the property ID
  232.         //                                        that we wish to specify.
  233.         //
  234.         // This time we pass 'false' to MakeObjectSpecifier so that it will NOT dispose
  235.         // of its inputs when it is done.  Doing this leaves the keyData and ofSpecifier
  236.         // descriptors intact; we dispose of the key data, but leave the specifier that
  237.         // was passed into this function the responsibility of the caller.
  238.         //
  239.         specifier.MakeObjectSpecifier(cProperty, ofSpecifier, formPropertyID, keyData, false);
  240.         keyData.Dispose();
  241.     }
  242.     Catch(err)
  243.     {
  244.         //
  245.         // Note that 'MakeObjectSpecifier' might fail (out of memory, for example),
  246.         // so we must catch failures to dispose of the key data descriptor if necessary.
  247.         //
  248.         keyData.Dispose();
  249.         Throw(err);
  250.     }
  251.         
  252.     return specifier;
  253. } // MakeSpecifierForPropertyOfSpecifier 
  254.  
  255. //----------------------------------------------------------------------------------------
  256. // MakeSpecifierForPropertyOfSelection: 
  257. //
  258. //    This function makes an object specifier for "property of selection"
  259. //----------------------------------------------------------------------------------------
  260. TDescriptor MakeSpecifierForPropertyOfSelection(DescType property)
  261. {
  262.     TDescriptor specifier;
  263.     TDescriptor selectionSpecifier; 
  264.     TDescriptor keyData;
  265.     OSErr err = noErr;
  266.     
  267.     //
  268.     // Build an object specifier for "selection of <null container>"
  269.     //
  270.     selectionSpecifier = MakeSpecifierForSelection();
  271.     
  272.     Try
  273.     {
  274.         //
  275.         // Next, make a specifier for "property of selection"
  276.         //
  277.         specifier = MakeSpecifierForPropertyOfSpecifier(property, selectionSpecifier);
  278.         selectionSpecifier.Dispose();
  279.     }
  280.     Catch(err)
  281.     {
  282.         //
  283.         // If 'MakeSpecifierForPropertyOfSpecifier' fails, we must dispose
  284.         // of selectionSpecifier.
  285.         //
  286.         selectionSpecifier.Dispose();
  287.         Throw(err);
  288.     }
  289.     
  290.     return specifier;
  291. } // MakeSpecifierForPropertyOfSelection 
  292.  
  293. TDescriptor GetFinderSelection(DescType desiredType);
  294.  
  295. #ifdef SOMEWHEREELSE
  296.  
  297. //----------------------------------------------------------------------------------------
  298. // GetFinderSelection: 
  299. //
  300. // This routine asks the Finder for the list of selected items; 'desiredType' specifies
  301. // the data type that is desired in the result that is sent back; choices include
  302. // typeObjectSpecifier, typeFSS, and typeAlias.
  303. //----------------------------------------------------------------------------------------
  304. TDescriptor GetFinderSelection(DescType desiredType)
  305. {
  306.     TAEvent ae;
  307.     TAEvent reply;
  308.     TDescriptor target;
  309.     TDescriptor directObjectSpecifier;
  310.     TDescriptor dataDescriptor;
  311.     TDescriptor selectedItems;
  312.     OSErr err = noErr;
  313.     
  314.     Try
  315.     {
  316.         //
  317.         // Get the address of the Finder and make a "Set Data" event
  318.         //
  319.         target = GetAddressOfFinder();
  320.         ae.MakeAppleEvent(kAECoreSuite, kAEGetData, target);
  321.         target.Dispose();
  322.         
  323.         //
  324.         // Make an object specifier for the property we want to set,
  325.         // and put it into the direct object of our event
  326.         //
  327.         directObjectSpecifier = MakeSpecifierForSelection();
  328.         ae.PutDescriptor(keyDirectObject, directObjectSpecifier);
  329.         directObjectSpecifier.Dispose();
  330.         
  331.         //
  332.         // Request FSSpecs back from the Get Data event.
  333.         //
  334.         // The Object Support Library requires that the
  335.         // requested data type be stored in a list of types,
  336.         // so we coerce the 'typeType' descriptor into a list
  337.         // of one descriptor.  The Finder does not require
  338.         // this, but some other applications might, since it
  339.         // is part of the OSL spec.
  340.         //
  341.         dataDescriptor.MakeDescType(desiredType);
  342.         dataDescriptor.Coerce(typeAEList);
  343.         ae.PutDescriptor(keyAERequestedType, dataDescriptor);
  344.         dataDescriptor.Dispose();
  345.         
  346.         //
  347.         // It is generally a bad idea to use kAEWaitReply,
  348.         // because it prevents your application from processing
  349.         // other events.  There are a number of potential solutions:
  350.         //
  351.         //        Use kAEQueueReply, and process the reply when it is
  352.         //        returned from WaitNextEvent.  The disadvantage is that
  353.         //        the processing of the reply must be done separately
  354.         //        from the code that sets up to do the send
  355.         //
  356.         //        Provide a filter proc to AESend that processes
  357.         //        events while your application is waiting for the reply.
  358.         //        The disadvantage of doing this is that the event
  359.         //        handling of your application is complicated, and
  360.         //        may become nested if events need to be sent to
  361.         //        process an incoming message
  362.         //
  363.         //        Pass kImmediateTimeout as the timeout value for
  364.         //        AESend.  When the reply event is accessed, an
  365.         //        error is returned if the reply has not yet arrived.
  366.         //        This method is best employeed in conjunction with
  367.         //        a threads package, so that the thread that sends
  368.         //        the message can block until the reply arrives.
  369.         //        See the article on Futures by Michael Gough in
  370.         //        d e v e l o p  issue #7.
  371.         //
  372.         ae.Send(&reply, kAEWaitReply);
  373.         
  374.         //
  375.         // Extract the result from the reply
  376.         //    
  377.         selectedItems = reply.GetDescriptor(keyAEResult);
  378.         reply.Dispose();
  379.     }
  380.     Catch(err)
  381.     {
  382.         target.Dispose();
  383.         directObjectSpecifier.Dispose();
  384.         dataDescriptor.Dispose();
  385.         reply.Dispose();
  386.  
  387.         Throw(err);
  388.     }
  389.     
  390.     return selectedItems;
  391. } // GetFinderSelection
  392.  
  393. #endif
  394.  
  395. //----------------------------------------------------------------------------------------
  396. // CountItemsInContainer
  397. //
  398. //    Returns the number of items of class 'desiredClass' inside the specified
  399. //    container.  The target application is specified in the parameter list.
  400. //----------------------------------------------------------------------------------------
  401. long CountItemsInContainer(DescType desiredClass, TDescriptor inContainer, TDescriptor target)
  402. {
  403.     TAEvent ae;
  404.     TAEvent reply;
  405.     TDescriptor keyData;
  406.     OSErr err = noErr;
  407.     long theCount = 0;
  408.     
  409.     Try
  410.     {
  411.         //
  412.         // Make a "Count elements" event
  413.         //
  414.         ae.MakeAppleEvent(kAECoreSuite, kAECountElements, target);
  415.         
  416.         //
  417.         // Put the direct object specifier into the direct object of our event
  418.         //
  419.         ae.PutDescriptor(keyDirectObject, inContainer);
  420.         
  421.         //
  422.         // Specify the class of things we want to count
  423.         //
  424.         keyData.MakeDescType(desiredClass);
  425.         ae.PutDescriptor(keyAEObjectClass, keyData);
  426.         keyData.Dispose();
  427.         
  428.         //
  429.         // Ask the question.  kAEWaitReply without filter procs is evil.
  430.         //
  431.         ae.Send(&reply, kAEWaitReply);
  432.         
  433.         //
  434.         // Extract the result out of the reply
  435.         //
  436.         theCount = reply.GetLongParameter(keyAEResult);
  437.     }
  438.     Catch(err)
  439.     {
  440.         //
  441.         // Any of a number of routines that we call above could
  442.         // fail; if they do, we need to dispose of any object
  443.         // that we created.
  444.         //
  445.         ae.Dispose();
  446.         reply.Dispose();
  447.         keyData.Dispose();
  448.         
  449.         Throw(err);
  450.     }
  451.     
  452.     return theCount;
  453. } // CountItemsInContainer
  454.  
  455. //----------------------------------------------------------------------------------------
  456. // RotateIconsTrick
  457. //----------------------------------------------------------------------------------------
  458. void RotateIconsTrick()
  459. {
  460.     TDescriptor frontWindowSpecifier;
  461.     TDescriptor itemNOfFrontWindowSpecifier;
  462.     TDescriptor iconOfItemNSpecifier;
  463.     TAEvent ae;
  464.     TAEvent reply;
  465.     TDescriptor target;
  466.     TDescriptor iconFamilyForFirstItem;
  467.     long itemsInFrontWindow;
  468.     OSErr err = noErr;
  469.     
  470.     Try
  471.     {
  472.         //
  473.         // Make the address of the finder, and an object specifier to
  474.         // the frontmost window.  We will use these descriptors a number
  475.         // of times.
  476.         //
  477.         target = GetAddressOfFinder();
  478.         frontWindowSpecifier = MakeSpecifierForFrontWindow();
  479.         
  480.         //
  481.         // Ask the Finder how many items are in the front window
  482.         //
  483.         itemsInFrontWindow = CountItemsInContainer(cObject, frontWindowSpecifier, target);
  484.         
  485.         //
  486.         // Get an icon family for the first item in the frontmost window
  487.         // and save it away
  488.         //
  489.         ae.MakeAppleEvent(kAECoreSuite, kAEGetData, target);
  490.         
  491.         //
  492.         // Set the direct object for this event to 'icon of item 1 of frontWindowSpecifier'
  493.         //
  494.         itemNOfFrontWindowSpecifier = MakeSpecifierForIndexedItem(cObject, 1, frontWindowSpecifier);
  495.         iconOfItemNSpecifier = MakeSpecifierForPropertyOfSpecifier(pIconBitmap, itemNOfFrontWindowSpecifier);
  496.         ae.PutDescriptor(keyDirectObject, iconOfItemNSpecifier);
  497.         iconOfItemNSpecifier.Dispose();
  498.         itemNOfFrontWindowSpecifier.Dispose();
  499.  
  500.         //
  501.         // See notes on waitreply, elsewhere
  502.         //
  503.         ae.Send(&reply, kAEWaitReply);
  504.         
  505.         //
  506.         // Snarf the icon family out of the reply
  507.         //
  508.         iconFamilyForFirstItem = reply.GetDescriptor(keyAEResult);
  509.         
  510.         //
  511.         // Next, loop through the other items and set each's icon to
  512.         // that of its neighbor
  513.         //
  514.         for(long i=2; i<=itemsInFrontWindow; ++i)
  515.         {
  516.             //
  517.             // Set the icon of item i-1 to the icon of item i.
  518.             // Note that we could get an item from the Finder with a Get Data event,
  519.             // then send a separate Set Data event; however, it's faster to tell the
  520.             // Finder to set the icon of one item to be the icon of another item.
  521.             // To do this, we will set keyAEData to be an object specifier rather than
  522.             // literal data, and the Finder will figure out what's intended
  523.             //
  524.             ae.MakeAppleEvent(kAECoreSuite, kAESetData, target);
  525.  
  526.             //
  527.             // Set the direct object for this event to 'icon of item (i - 1) of frontWindowSpecifier'
  528.             //
  529.             itemNOfFrontWindowSpecifier = MakeSpecifierForIndexedItem(cObject, i - 1, frontWindowSpecifier);
  530.             iconOfItemNSpecifier = MakeSpecifierForPropertyOfSpecifier(pIconBitmap, itemNOfFrontWindowSpecifier);
  531.             ae.PutDescriptor(keyDirectObject, iconOfItemNSpecifier);
  532.             iconOfItemNSpecifier.Dispose();
  533.             itemNOfFrontWindowSpecifier.Dispose();
  534.             
  535.             //
  536.             // Set the key data for this event to 'icon of item i of frontWindowSpecifier'
  537.             //
  538.             itemNOfFrontWindowSpecifier = MakeSpecifierForIndexedItem(cObject, i, frontWindowSpecifier);
  539.             iconOfItemNSpecifier = MakeSpecifierForPropertyOfSpecifier(pIconBitmap, itemNOfFrontWindowSpecifier);
  540.             ae.PutDescriptor(keyAEData, iconOfItemNSpecifier);
  541.             iconOfItemNSpecifier.Dispose();
  542.             itemNOfFrontWindowSpecifier.Dispose();
  543.  
  544.             //
  545.             // We send this set data 'wait reply' because we don't want to blast
  546.             // a bunch of events at the Finder all at once; we want to make sure
  547.             // that one 'set data' finishes before the next is sent.
  548.             //
  549.             ae.Send(&reply, kAEWaitReply);
  550.         }
  551.         
  552.         //
  553.         // Finally, set the icon of the last item in the front window
  554.         // to the icon we saved above the loop.
  555.         //
  556.         ae.MakeAppleEvent(kAECoreSuite, kAESetData, target);
  557.         
  558.         //
  559.         // Set the direct object for this event to 'icon of item itemsInFrontWindow of frontWindowSpecifier'
  560.         //
  561.         itemNOfFrontWindowSpecifier = MakeSpecifierForIndexedItem(cObject, itemsInFrontWindow, frontWindowSpecifier);
  562.         iconOfItemNSpecifier = MakeSpecifierForPropertyOfSpecifier(pIconBitmap, itemNOfFrontWindowSpecifier);
  563.         ae.PutDescriptor(keyDirectObject, iconOfItemNSpecifier);
  564.         iconOfItemNSpecifier.Dispose();
  565.         itemNOfFrontWindowSpecifier.Dispose();
  566.         
  567.         //
  568.         // This time, the key data is the actual icon family to set the icon to,
  569.         // not an object specifier
  570.         //
  571.         ae.PutDescriptor(keyAEData, iconFamilyForFirstItem);
  572.         iconFamilyForFirstItem.Dispose();
  573.  
  574.         //
  575.         // The reply isn't actually filled in due to the kAENoReply flag
  576.         //
  577.         ae.Send(&reply, kAENoReply);
  578.         
  579.         //
  580.         // Dispose the items we used for several events
  581.         //
  582.         target.Dispose();
  583.         frontWindowSpecifier.Dispose();
  584.     }
  585.     Catch(err)
  586.     {
  587.         //
  588.         // Any of a number of routines that we call above could
  589.         // fail; if they do, we need to dispose of any object
  590.         // that we created.
  591.         //
  592.         target.Dispose();
  593.         frontWindowSpecifier.Dispose();
  594.         iconFamilyForFirstItem.Dispose();
  595.         
  596.         Throw(err);
  597.     }
  598. } // RotateIconsTrick
  599.  
  600. //----------------------------------------------------------------------------------------
  601. // SetDescTypePropertyOfSpecifier: 
  602. //
  603. //    This function sets an object specified by the object specifier provided to
  604. //    a new value, given as a descriptor type.
  605. //----------------------------------------------------------------------------------------
  606. void SetDescTypePropertyOfSpecifier(TDescriptor directObjectSpecifier, DescType newValue)
  607. {
  608.     TAEvent ae;
  609.     TAEvent reply;
  610.     TDescriptor target;
  611.     TDescriptor dataDescriptor;
  612.     OSErr err = noErr;
  613.     
  614.     Try
  615.     {
  616.         //
  617.         // Get the address of the Finder and make a "Set Data" event
  618.         //
  619.         target = GetAddressOfFinder();
  620.         ae.MakeAppleEvent(kAECoreSuite, kAESetData, target);
  621.         target.Dispose();
  622.         
  623.         //
  624.         // Put the direct object specifier into the direct object of our event
  625.         //
  626.         ae.PutDescriptor(keyDirectObject, directObjectSpecifier);
  627.         
  628.         //
  629.         // Put the new value into the key data of the "Set Data" event
  630.         //
  631.         dataDescriptor.MakeDescType(newValue);
  632.         ae.PutDescriptor(keyAEData, dataDescriptor);
  633.         dataDescriptor.Dispose();
  634.         
  635.         //
  636.         // The reply isn't actuall filled in due to the kAENoReply flag
  637.         //
  638.         ae.Send(&reply, kAENoReply);
  639.     }
  640.     Catch(err)
  641.     {
  642.         //
  643.         // Any of a number of routines that we call above could
  644.         // fail; if they do, we need to dispose of any object
  645.         // that we created.
  646.         //
  647.         target.Dispose();
  648.         dataDescriptor.Dispose();
  649.         ae.Dispose();
  650.         
  651.         Throw(err);
  652.     }
  653. } // SetDescTypePropertyOfSpecifier 
  654.  
  655. //----------------------------------------------------------------------------------------
  656. // SetDescTypePropertyOfFinderSelection: 
  657. //
  658. //    This function sets a property of the Finder's selection.  We set the property
  659. //    by sending the Finder a single set data event; we do not care what the return
  660. //    value of the "Set Data" event is.
  661. //----------------------------------------------------------------------------------------
  662. void SetDescTypePropertyOfFinderSelection(DescType property, DescType newValue)
  663. {
  664.     TDescriptor directObjectSpecifier;
  665.     OSErr err = noErr;
  666.     
  667.     //
  668.     // Make an object specifier for the property we want to set,
  669.     // and call SetDescTypePropertyOfSpecifier (above) to send
  670.     // the Finder a 'Set Data' event.
  671.     //
  672.     directObjectSpecifier = MakeSpecifierForPropertyOfSelection(property);
  673.     
  674.     Try
  675.     {
  676.         //
  677.         // The actual AESend is done by 'SetDescTypePropertyOfSpecifier', above.
  678.         //
  679.         SetDescTypePropertyOfSpecifier(directObjectSpecifier, newValue);
  680.         directObjectSpecifier.Dispose();
  681.     }
  682.     Catch(err)
  683.     {
  684.         directObjectSpecifier.Dispose();
  685.         Throw(err);
  686.     }
  687. } // SetDescTypePropertyOfFinderSelection 
  688.  
  689. //----------------------------------------------------------------------------------------
  690. // UpdateChangedObject: 
  691. //----------------------------------------------------------------------------------------
  692. void UpdateChangedObject(FSSpec& itemsFSSpec)
  693. {
  694.     TAEvent ae;
  695.     TAEvent reply;
  696.     TDescriptor target;
  697.     TDescriptor directObjectSpecifier;
  698.     OSErr err = noErr;
  699.     
  700.     Try
  701.     {
  702.         //
  703.         // Get the address of the Finder and make an "Update" event
  704.         //
  705.         target = GetAddressOfFinder();
  706.         ae.MakeAppleEvent(kAEFinderSuite, kAEUpdate, target);
  707.         target.Dispose();
  708.         
  709.         //
  710.         // Most scriptable applications require the direct
  711.         // object of an event to always be an object
  712.         // specifier.  The Finder is special, though; it
  713.         // will accept FSSpecs and alias records as well.
  714.         //
  715.         directObjectSpecifier.MakeFSS(itemsFSSpec);
  716.         ae.PutDescriptor(keyDirectObject, directObjectSpecifier);
  717.         directObjectSpecifier.Dispose();
  718.         
  719.         //
  720.         // The reply isn't actuall filled in due to the kAENoReply flag
  721.         //
  722.         ae.Send(&reply, kAENoReply);
  723.     }
  724.     Catch(err)
  725.     {
  726.         //
  727.         // Any of a number of routines that we call above could
  728.         // fail; if they do, we need to dispose of any object
  729.         // that we created.
  730.         //
  731.         target.Dispose();
  732.         directObjectSpecifier.Dispose();
  733.         ae.Dispose();
  734.         
  735.         Throw(err);
  736.     }
  737. } // UpdateChangedObject
  738.  
  739. //
  740. // Listing 3 returns owner of front window
  741. //
  742. TDescriptor Listing3();
  743.  
  744. void RevealOwnerOfFrontWindow()
  745. {
  746.     TAEvent ae;
  747.     
  748.     TDescriptor target = GetAddressOfFinder();
  749.     ae.MakeAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, target);
  750.     target.Dispose();
  751.  
  752.     TDescriptor ownerOfFrontWindow = Listing3();
  753.     
  754.     ae.PutDescriptor(keyDirectObject, ownerOfFrontWindow);
  755.     ownerOfFrontWindow.Dispose();
  756.  
  757.     TAEvent reply;
  758.     ae.Send(&reply, kAENoReply);
  759. }
  760.  
  761. //
  762. // Listing 4 deletes the custom icon of every item in the selection
  763. //
  764. void Listing4();
  765.  
  766. void RemoveCustomIconFromSelection()
  767. {
  768.     Listing4();
  769. }
  770.  
  771. //
  772. // Listing 6 shares every folder in the selection
  773. //
  774. void Listing6();
  775.  
  776. void ShareSelectedFolders()
  777. {
  778.     Listing6();
  779. }
  780.  
  781.